package com.hy.generator.service;

import com.hy.generator.common.exception.BusinessException;
import com.hy.generator.common.utils.FileUtil;
import com.hy.generator.dfs.ColumnType;
import com.hy.generator.dto.ParameterDTO;
import com.hy.generator.param.BuildParam;
import com.hy.generator.param.ParameterParam;
import com.hy.generator.utils.FreeMarkerUtil;
import com.opencsv.CSVReader;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

@Slf4j
@Service
public class BuildService {

    private static final String GENERAL_CODE_DIR = "general-code";
    private static final String MODEL_CODE_DIR = "model-code";

    public void build(BuildParam buildParam, MultipartFile[] files, HttpServletResponse response) throws IOException {
        String projectCode = buildParam.getProjectCode();
        String packageCode = buildParam.getPackageCode();

        Map<String, Object> params = new HashMap<>(16);
        params.put("projectCode", projectCode);
        params.put("projectName", buildParam.getProjectName());
        params.put("packageCode", packageCode);
        //projectCode首字母大写和中划线后面的字母大写
        String projectCodeUpper = FreeMarkerUtil.toPascalCase(projectCode);
        params.put("projectCodeUpper", projectCodeUpper);
        params.put("databaseName", projectCode.replace("-", "_"));
        String rootPath = FreeMarkerUtil.isWindows() ? "D:\\hy" : "/hy";
        String basePath = rootPath + File.separator + System.currentTimeMillis() + File.separator;
        String projectPath = basePath + projectCode;
        // 先处理固定的部分
        Map<String, String> replace = new HashMap<>(16);
        replace.put("${projectCode}", projectCode);
        replace.put("${projectCodeUpper}", projectCodeUpper);
        replace.put("${packageCode}", packageCode);
        FreeMarkerUtil.findTemplateFilePaths(GENERAL_CODE_DIR).forEach(templatePath -> {
            String outputPath = FreeMarkerUtil.calculateOutputPath(templatePath, projectPath, GENERAL_CODE_DIR, replace);
            FreeMarkerUtil.process(templatePath, params, outputPath);
        });

        Arrays.asList(files).forEach(file -> {
            File csvFile = new File(basePath + file.getOriginalFilename());
            try {
                file.transferTo(csvFile);
            } catch (IOException e) {
                throw new BusinessException(e.getMessage());
            }
            try (CSVReader reader = new CSVReader(new FileReader(csvFile))) {
                CsvToBean<ParameterParam> csvToBean = new CsvToBeanBuilder<ParameterParam>(reader)
                        .withType(ParameterParam.class)
                        .withIgnoreLeadingWhiteSpace(true)
                        .build();

                List<ParameterParam> parameterParams = csvToBean.parse();
                boolean containDate = false;
                boolean containString = false;
                boolean containNotString = false;
                List<ParameterDTO> parameterDTOS = new ArrayList<>();
                for (ParameterParam param : parameterParams) {
                    ColumnType columnType = ColumnType.valueOf(param.getType());
                    parameterDTOS.add(ParameterDTO.builder()
                            .column(param.getColumn())
                            .fieldName(FreeMarkerUtil.toCamelCase(param.getColumn()))
                            .description(param.getDescription())
                            .fieldType(columnType.getField())
                            .build());
                    if (columnType == ColumnType.DATE) {
                        containDate = true;
                    }
                    if (columnType == ColumnType.VAR_CHAR) {
                        containString = true;
                    } else {
                        containNotString = true;
                    }
                }
                if (parameterDTOS.isEmpty()) {
                    return;
                }
                params.put("containDate", containDate);
                params.put("containString", containString);
                params.put("containNotString", containNotString);
                params.put("parameters", parameterDTOS);

                String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));
                String tableCode;
                String objName;
                if (fileName.contains("-")) {
                    String[] split = fileName.split("-");
                    tableCode = split[1];
                    objName = split[0];
                } else {
                    tableCode = fileName;
                    objName = FreeMarkerUtil.toPascalCase(fileName);
                }
                params.put("tableCode", tableCode);
                String classCode = FreeMarkerUtil.toPascalCase(tableCode);
                params.put("classCode", classCode);
                params.put("urlCode", FreeMarkerUtil.toCamelCase(tableCode));
                params.put("objCode", FreeMarkerUtil.toCamelCase(tableCode));
                params.put("objName", objName);
                replace.put("${classCode}", classCode);

                FreeMarkerUtil.findTemplateFilePaths(MODEL_CODE_DIR).forEach(templatePath -> {
                    String outputPath = FreeMarkerUtil.calculateOutputPath(templatePath, projectPath, MODEL_CODE_DIR, replace);
                    FreeMarkerUtil.process(templatePath, params, outputPath);
                });
                csvFile.delete();
            } catch (IOException e) {
                throw new BusinessException(e.getMessage());
            }
        });

        FileUtil.download(projectPath, response);

    }


}


